package com.hzh.page.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzh.page.common.exception.Assert;
import com.hzh.page.common.exception.ResponseEnum;
import com.hzh.page.common.utils.JwtUtils;
import com.hzh.page.dao.AuthenticationMenuMapper;
import com.hzh.page.pojo.AuthenticationMenuEntity;
import com.hzh.page.pojo.AuthenticationRoleMenuEntity;
import com.hzh.page.pojo.AuthenticationUserRoleEntity;
import com.hzh.page.service.AuthenticationMenuService;
import com.hzh.page.service.AuthenticationRoleMenuService;
import com.hzh.page.service.AuthenticationUserRoleService;
import com.hzh.page.vo.AuthenticationMenuVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 胡泽华
 */
@Slf4j
@Service("AuthenticationMenuService")
public class AuthenticationMenuServiceImpl extends ServiceImpl<AuthenticationMenuMapper, AuthenticationMenuEntity> implements AuthenticationMenuService {
    @Resource
    AuthenticationMenuMapper authenticationMenuMapper;

    @Resource
    private AuthenticationUserRoleService userRoleService;

    @Resource
    private AuthenticationRoleMenuService roleMenuService;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public List<AuthenticationMenuVO> listAuthenticationMenu() {

        List<AuthenticationMenuEntity> menuEntities = this.baseMapper.selectList(null);
        List<AuthenticationMenuVO> collect = menuEntities.stream().map(item -> {
            AuthenticationMenuVO authenticationMenuVO = new AuthenticationMenuVO();
            BeanUtils.copyProperties(item, authenticationMenuVO);
            if (item.getRightId() == 0) {
                authenticationMenuVO.setChildren(getChildrenList(item.getId(), menuEntities));
                return authenticationMenuVO;
            }
            return null;
        }).filter(item -> {
            return item != null;
        }).collect(Collectors.toList());

        return collect;
    }

    @Override
    public void deleteAuthenticationMenu(Integer id) {
        AuthenticationMenuEntity authenticationMenuEntity = this.baseMapper.selectById(id);
        //如果不存在上级，则将下级级联删除
        if (authenticationMenuEntity.getRightId() == 0) {
            List<Integer> childrenIds = authenticationMenuMapper.selectChildIds(id);
            if (childrenIds.size() != 0) {
                this.baseMapper.deleteBatchIds(childrenIds);
            }
        }
        this.baseMapper.deleteById(id);
    }

    /**
     * 通过登录用户token判断是否拥有权限
     */
    @Override
    public boolean hashAuthority(HttpServletRequest request, String routeKey) {
        ValueOperations<String, String> ops = redisTemplate.opsForValue();
        String token = request.getHeader("token");
        Integer userId = JwtUtils.getUserId(token);
        AuthenticationUserRoleEntity userRoleEntity = userRoleService.getOne(new QueryWrapper<AuthenticationUserRoleEntity>().eq("user_id", userId));
        String roleMenuListFromRedis = ops.get("roleMenuList" + userRoleEntity.getRoleId());
        List<AuthenticationRoleMenuEntity> roleMenuList;

        if (!StringUtils.isEmpty(roleMenuListFromRedis)){
            log.info("redis缓存命中{}","roleMenuList" + userRoleEntity.getRoleId());
            roleMenuList = JSON.parseObject(roleMenuListFromRedis, new TypeReference<List<AuthenticationRoleMenuEntity>>(){});
        }else {
            roleMenuList = roleMenuService.list(new QueryWrapper<AuthenticationRoleMenuEntity>().eq("role_id", userRoleEntity.getRoleId()));
            ops.setIfAbsent("roleMenuList"+userRoleEntity.getRoleId(), JSON.toJSONString(roleMenuList),1, TimeUnit.DAYS);
        }

        Assert.isTrue(!roleMenuList.isEmpty(), ResponseEnum.USER_RIGHT_ERROR);
        List<Integer> menuIds = roleMenuList.stream().map(AuthenticationRoleMenuEntity::getMenuId).collect(Collectors.toList());
        String roleMenuFromRedis = ops.get("menus" + userRoleEntity.getRoleId());
        List<AuthenticationMenuEntity> roleMenuList2;
        if (!StringUtils.isEmpty(roleMenuFromRedis)){
            log.info("redis缓存命中{}","menus" + userRoleEntity.getRoleId());
            roleMenuList2 = JSON.parseObject(roleMenuFromRedis, new TypeReference<List<AuthenticationMenuEntity>>(){});
        }else {
            roleMenuList2 = this.baseMapper.selectBatchIds(menuIds);
            ops.setIfAbsent("menus" + userRoleEntity.getRoleId(), JSON.toJSONString(roleMenuList2),1, TimeUnit.DAYS);
        }

        Set<String> collect = roleMenuList2.stream().map(AuthenticationMenuEntity::getRouteKey).collect(Collectors.toSet());
        return collect.contains(routeKey);
    }

    @Override
    public void updateAuthenticationMenu(Integer id, Integer pagepermisson) {
        AuthenticationMenuEntity authenticationMenuEntity = baseMapper.selectById(id);
        if (authenticationMenuEntity != null) {
            authenticationMenuEntity.setPagepermisson(pagepermisson);
            this.baseMapper.updateById(authenticationMenuEntity);
        }
    }

    private List<AuthenticationMenuEntity> getChildrenList(Integer pid, List<AuthenticationMenuEntity> selectList) {
        List<AuthenticationMenuEntity> childrenList = selectList.stream().filter(item ->
                (item.getRightId() != 0 && item.getRightId().equals(pid))
        ).collect(Collectors.toList());
        return childrenList;
    }

//    private List<AuthenticationMenuEntity> getChildrenList(Integer pid, List<AuthenticationMenuEntity> selectList){
//        List<AuthenticationMenuEntity> childrenList = selectList.stream().filter(item ->
//                (item.getRightId() != 0 && item.getRightId().equals(pid))
//        ).collect(Collectors.toList());
//        return childrenList;
//    }
}
